package parsers;

import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import datamodel.Entry;
import datamodel.TVShow;

public class NameParser {
	/** The various ways a TV show can be named */
	NamingScheme[] tvNamingSchemes = {
			/* Show-S1-E1-Name.avi */
			new NamingScheme("(.*)-[sS](\\d*)-[eE](\\d*)-(.*)", 1, 2, 3),

			/* Show-S1-E1.avi */
			new NamingScheme("(.*)-[sS](\\d*)-[eE](\\d*)", 1, 2, 3),

			/* Show S1-E1-Name.avi */
			new NamingScheme("(.*) [sS](\\d*)-[eE](\\d*)-(.*)", 1, 2, 3),

			/* Show S1-E1.avi */
			new NamingScheme("(.*) [sS](\\d*)-[eE](\\d*)", 1, 2, 3),

			/* Show - S01-E01 - Name.avi */
			new NamingScheme("(.*)\\s(-?)\\s[sS](\\d*)-[eE](\\d*)\\s-\\s(.*)",
					1, 3, 4),

			/* Show - S01E01 - Name.avi */
			new NamingScheme("(.*)\\s-\\s[sS](\\d*)[eE](\\d*)\\s-\\s(.*)", 1,
					2, 3),

			/* Show.S01E01.Name.avi */
			new NamingScheme("(.*).S(\\d*)E(\\d*)(.*)", 1, 2, 3),

	};

	/** Vector to keep track of which TV shows the user has been queried about */
	Vector<TVShow> tvShows;

	/**
	 * Constructor
	 * 
	 * @param tvShows
	 *            Vector to keep track of which TV shows the user has been
	 *            queried about
	 */
	public NameParser(Vector<TVShow> tvShows) {
		this.tvShows = tvShows;
	}

	/**
	 * Executes parsing of the entry's name to see if it is a TV show or movie
	 * 
	 * @param entry
	 *            The entry to check
	 */
	public void execute(Entry entry) {
		// Get the title from the filename
		String title = processFileName(entry);

		// See if the filename is a TV show
		if (processTVShow(entry, title) == false) {
			// Make sure there isn't extra stuff in the title
			title = processTitle(title);

			// Set the title
			entry.setTitle(title);
		}
	}

	/**
	 * Gets the title of the entry from the filename
	 * 
	 * @param entry
	 *            The entry to parse
	 * @return The title of the entry
	 */
	private String processFileName(Entry entry) {
		String filename = entry.getFilename();

		// Figure out the title from the filename
		Pattern pattern = Pattern.compile("(.*)/(.*)\\.");
		Matcher matcher = pattern.matcher(filename);

		String title = new String();

		if (matcher.find()) {
			title = matcher.group(2);
		}
		return title;
	}

	/**
	 * Process the entry as a TV show to get it season and episode number
	 * 
	 * @param entry
	 *            The entry to parse
	 * @param title
	 *            The title of the entry
	 * @return Whether or the not the entry is a TV show
	 */
	private boolean processTVShow(Entry entry, String title) {
		Pattern pattern;
		Matcher matcher;
		for (NamingScheme namingScheme : tvNamingSchemes) {
			pattern = Pattern.compile(namingScheme.getRegex());
			matcher = pattern.matcher(title);

			try {
				String showName = matcher.group(namingScheme.getShowNameGroup());
				int season = Integer.parseInt(matcher.group(namingScheme
						.getSeasonGroup()));
				int episode = Integer.parseInt(matcher.group(namingScheme
						.getEpisodeGroup()));

				entry.setTitle(showName);
				entry.setSeason(season);
				entry.setEpisode(episode);
				entry.setTVShow(true);

				// Figure out which TV show this episode belongs to
				for (TVShow show : tvShows) {
					if (showName.equals(show.getShowName())) {
						show.addEpisode(entry);
					}
				}

				// It must be a new show so create one
				if (entry.getShow() == null) {
					TVShow show = new TVShow(showName);
					tvShows.add(show);
					show.addEpisode(entry);
					entry.setShow(show);
				}

				return true;
			} catch (Exception e) {
				System.out.println( "There was an error while processing " + title + ".  This is OK.  Will try the next naming scheme." );
			}

		}

		return false;
	}

	/**
	 * Processes the title to remove any cd or disc at the end of the name
	 * 
	 * @param title
	 *            The title to work with
	 * @return The title with any cd or disc removed
	 */
	private String processTitle(String title) {
		if (title.toLowerCase().indexOf("-cd") != -1) {
			title = title.substring(0, title.toLowerCase().indexOf("-cd"));
		} else if (title.toLowerCase().indexOf(" cd") != -1) {
			title = title.substring(0, title.toLowerCase().indexOf(" cd"));
		} else if (title.toLowerCase().indexOf(" disc") != -1) {
			title = title.substring(0, title.toLowerCase().indexOf(" disc"));
		} else if (title.toLowerCase().indexOf("-disc") != -1) {
			title = title.substring(0, title.toLowerCase().indexOf("-disc"));
		}

		return title;
	}

	/**
	 * This class makes it easier to deal with the various ways a TV show can be
	 * named
	 */
	class NamingScheme {
		String regex;

		int showNameGroup;
		int seasonGroup;
		int episodeGroup;

		/**
		 * Constructor
		 * 
		 * @param regex
		 *            The regular expression to run on the file
		 * @param showNameGroup
		 *            The number corresponding to the show's name
		 * @param seasonGroup
		 *            The number corresponding to the show's season number
		 * @param episodeGroup
		 *            THe number corresponding to the show's episode number
		 */
		public NamingScheme(String regex, int showNameGroup, int seasonGroup,
				int episodeGroup) {
			super();
			this.regex = regex;
			this.showNameGroup = showNameGroup;
			this.seasonGroup = seasonGroup;
			this.episodeGroup = episodeGroup;
		}

		public String getRegex() {
			return regex;
		}

		public void setRegex(String regex) {
			this.regex = regex;
		}

		public int getShowNameGroup() {
			return showNameGroup;
		}

		public void setShowNameGroup(int showNameGroup) {
			this.showNameGroup = showNameGroup;
		}

		public int getSeasonGroup() {
			return seasonGroup;
		}

		public void setSeasonGroup(int seasonGroup) {
			this.seasonGroup = seasonGroup;
		}

		public int getEpisodeGroup() {
			return episodeGroup;
		}

		public void setEpisodeGroup(int episodeGroup) {
			this.episodeGroup = episodeGroup;
		}

	}
}
